package top.kaoshanji.u1ch08b;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.lang.model.util.Elements;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 代码清单-u1ch08b-277页a：Author注解的处理器
 * author kaoshanji
 * ^_^
 * create time 2025/1/23 19:07
 */
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes("top.kaoshanji.u1ch08b.Author")
public class AuthorProcessor extends AbstractProcessor {

    private static final Logger logger = LogManager.getLogger(AuthorProcessor.class);

    private Map<String, Integer> countMap = new HashMap<>();
    private TypeElement authorElement;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        Elements elementUtils = processingEnv.getElementUtils();
        authorElement = elementUtils.getTypeElement("top.kaoshanji.u1ch08b.Author");
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        System.out.println("AuthorProcessor.process ;");

        Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(authorElement);

        for (Element element: elements) {
            processAuthor(element);
        }

        if (roundEnv.processingOver()) {
            for (Map.Entry<String, Integer> entry: countMap.entrySet()) {
                logger.info("...key:{} ===> value:{}...", entry.getKey(), entry.getValue());
            }
        }

        return true;
    }

    //-----------------private---------------------------

    private void processAuthor(Element element) {
        List<? extends AnnotationMirror> annotations = element.getAnnotationMirrors();
        for (AnnotationMirror mirror: annotations) {
            if (mirror.getAnnotationType().asElement().equals(authorElement)) {
                String name = (String) getAnnotationValue(mirror, "name");
                if (!countMap.containsKey(name)) {
                    countMap.put(name, 1);
                } else {
                    countMap.put(name, countMap.get(name) + 1);
                }
            }
        }
    }

    private Object getAnnotationValue(AnnotationMirror mirror, String name) {
        Map<? extends ExecutableElement, ? extends AnnotationValue> values = mirror.getElementValues();
        for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry: values.entrySet()) {
            ExecutableElement elem = entry.getKey();
            AnnotationValue value = entry.getValue();
            String elemName = elem.getSimpleName().toString();
            if (name.equals(elemName)) {
                return value.getValue();
            }
        }
        return null;
    }


}
